
// 缓存标签接口
export interface CacheTag {
  key: string;
  expire: number;
}

// 缓存配置接口
export interface CacheOptions {
  storageType?: 'sessionStorage' | 'localStorage';
  namespace?: string;
  defaultExpire?: number;
}

class Cache {
  // 存储处理器
  private storage: Storage;
  
  // 存储类型
  private storageType: 'sessionStorage' | 'localStorage';
  
  // 缓存命名空间
  private namespace: string;
  
  // 默认过期时间（秒）
  private defaultExpire: number;
  
  // 过期标签存储键
  private expireTagKey: string;

  constructor(options: CacheOptions = {}) {
    this.storageType = options.storageType || 'sessionStorage';
    this.namespace = options.namespace || 'UNI-APP-bjt';
    this.defaultExpire = options.defaultExpire || 0;
    this.expireTagKey = `${this.namespace}:TAG`;
    
    // 根据存储类型选择对应的存储对象
    this.storage = this.storageType === 'sessionStorage'
      ? window.sessionStorage 
      : window.localStorage;
    
    // 初始化时清除过期缓存
    this.clearExpiredCache();
  }

  /**
   * 获取当前时间戳（秒）
   */
  private getCurrentTimestamp(): number {
    return Math.floor(Date.now() / 1000);
  }

  /**
   * 安全地从存储中获取数据并解析
   * @param key 存储键名
   */
  private safeGet<T>(key: string): T | null {
    try {
      const value = this.storage.getItem(key);
      if (value === null) return null;
      return JSON.parse(value) as T;
    } catch (error) {
      console.warn(`Failed to parse cache for key ${key}:`, error);
      return null;
    }
  }

  /**
   * 安全地将数据序列化并存储
   * @param key 存储键名
   * @param value 要存储的值
   */
  private safeSet(key: string, value: any): boolean {
    try {
      this.storage.setItem(key, JSON.stringify(value));
      return true;
    } catch (error) {
      console.error(`Failed to set cache for key ${key}:`, error);
      return false;
    }
  }

  /**
   * 获取所有缓存标签
   */
  private getCacheTags(): CacheTag[] {
    try {
      const tagsStr = this.storage.getItem(this.expireTagKey);
      if (!tagsStr) return [];
      
      const tags = JSON.parse(tagsStr) as CacheTag[];
      return Array.isArray(tags) ? tags : [];
    } catch (error) {
      console.warn('Failed to get cache tags:', error);
      return [];
    }
  }

  /**
   * 保存缓存标签
   * @param tags 缓存标签数组
   */
  private saveCacheTags(tags: CacheTag[]): boolean {
    return this.safeSet(this.expireTagKey, tags);
  }

  /**
   * 设置缓存过期标签
   * @param key 缓存键名
   * @param expire 过期时间（秒）
   */
  private setExpireCacheTag(key: string, expire?: number): void {
    const expireTime = expire === undefined ? this.defaultExpire : expire;
    
    if (typeof expireTime !== 'number') {
      console.error('Expire time must be a number');
      return;
    }

    const tags = this.getCacheTags();
    const existingIndex = tags.findIndex(tag => tag.key === key);
    const timestamp = this.getCurrentTimestamp();
    
    // 计算实际过期时间戳
    const actualExpire = expireTime === 0 ? 0 : timestamp + expireTime;

    if (existingIndex >= 0) {
      // 更新现有标签
      tags[existingIndex].expire = actualExpire;
    } else {
      // 添加新标签
      tags.push({
        key,
        expire: actualExpire
      });
    }

    this.saveCacheTags(tags);
  }

  /**
   * 检查缓存是否过期
   * @param key 缓存键名
   * @param shouldDelete 是否删除过期缓存
   */
  private isCacheExpired(key: string, shouldDelete: boolean = true): boolean {
    try {
      const tags = this.getCacheTags();
      const tag = tags.find(t => t.key === key);
      const currentTime = this.getCurrentTimestamp();

      // 如果找不到标签，检查原始缓存是否存在
      if (!tag) {
        return this.storage.getItem(key) !== null;
      }

      // 永不过期的缓存
      if (tag.expire === 0) {
        return true;
      }

      // 检查是否过期
      const isExpired = tag.expire < currentTime;
      
      if (isExpired && shouldDelete) {
        this.clear(key);
      }

      return !isExpired;
    } catch (error) {
      console.warn(`Failed to check cache expiration for key ${key}:`, error);
      return false;
    }
  }

  /**
   * 设置缓存
   * @param key 缓存键名
   * @param data 缓存数据
   * @param expire 过期时间（秒），0表示永不过期
   */
  set<T>(key: string, data: T, expire?: number): boolean {
    if (data === undefined) {
      return true;
    }

    try {
      // 设置过期标签
      this.setExpireCacheTag(key, expire);
      
      // 存储数据
      return this.safeSet(key, data);
    } catch (error) {
      console.error(`Failed to set cache for key ${key}:`, error);
      return false;
    }
  }

  /**
   * 检查缓存是否存在
   * @param key 缓存键名
   * @param shouldDeleteExpired 是否删除过期缓存
   */
  has(key: string, shouldDeleteExpired: boolean = true): boolean {
    this.clearExpiredCache();
    return this.isCacheExpired(key, shouldDeleteExpired);
  }

  /**
   * 获取缓存
   * @param key 缓存键名
   * @param defaultValue 默认值或获取默认值的函数
   * @param expire 当使用默认值时的过期时间（秒）
   */
  get<T>(key: string, defaultValue?: T | (() => T), expire?: number): T | null {
    this.clearExpiredCache();
    
    try {
      // 检查缓存是否有效
      if (this.isCacheExpired(key)) {
        const data = this.safeGet<T>(key);
        if (data !== null) {
          return data;
        }
      }

      // 处理默认值
      if (typeof defaultValue === 'function') {
        const value = (defaultValue as () => T)();
        this.set(key, value, expire);
        return value;
      } else if (defaultValue !== undefined) {
        this.set(key, defaultValue, expire);
        return defaultValue;
      }

      return null;
    } catch (error) {
      console.error(`Failed to get cache for key ${key}:`, error);
      return null;
    }
  }

  /**
   * 删除指定缓存
   * @param key 缓存键名
   */
  clear(key: string): boolean {
    try {
      // 从存储中删除
      this.storage.removeItem(key);
      
      // 从过期标签中删除
      const tags = this.getCacheTags();
      const filteredTags = tags.filter(tag => tag.key !== key);
      
      if (filteredTags.length !== tags.length) {
        this.saveCacheTags(filteredTags);
      }
      
      return true;
    } catch (error) {
      console.error(`Failed to clear cache for key ${key}:`, error);
      return false;
    }
  }

  /**
   * 清除所有缓存
   */
  clearAll(): void {
    try {
      // 清除所有相关缓存
      const tags = this.getCacheTags();
      tags.forEach(tag => {
        this.storage.removeItem(tag.key);
      });
      
      // 清除过期标签
      this.storage.removeItem(this.expireTagKey);
    } catch (error) {
      console.error('Failed to clear all cache:', error);
    }
  }

  /**
   * 清除过期的缓存
   */
  private clearExpiredCache(): void {
    try {
      const tags = this.getCacheTags();
      const currentTime = this.getCurrentTimestamp();
      const validTags: CacheTag[] = [];
      const expiredKeys: string[] = [];

      // 筛选出有效的标签和过期的键
      tags.forEach(tag => {
        if (tag && (tag.expire === 0 || tag.expire > currentTime)) {
          validTags.push(tag);
        } else if (tag) {
          expiredKeys.push(tag.key);
        }
      });

      // 更新有效的标签
      if (validTags.length !== tags.length) {
        this.saveCacheTags(validTags);
      }

      // 删除过期的缓存
      expiredKeys.forEach(key => {
        this.storage.removeItem(key);
      });
    } catch (error) {
      console.warn('Failed to clear expired cache:', error);
    }
  }

  /**
   * 获取所有缓存键名
   */
  getKeys(): string[] {
    try {
      const tags = this.getCacheTags();
      return tags.map(tag => tag.key);
    } catch (error) {
      console.error('Failed to get cache keys:', error);
      return [];
    }
  }

  /**
   * 获取缓存大小（字节）
   */
  getSize(): number {
    try {
      let size = 0;
      for (let i = 0; i < this.storage.length; i++) {
        const key = this.storage.key(i);
        if (key) {
          const value = this.storage.getItem(key);
          if (value) {
            size += new Blob([key + value]).size;
          }
        }
      }
      return size;
    } catch (error) {
      console.error('Failed to get cache size:', error);
      return 0;
    }
  }
}

// 创建默认缓存实例
export const cache = new Cache();

export default cache;
